//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#pragma once

#include "Utils/Base/Meta.Common.h"
#include "UI/MetaData/Meta.Widgets.h"
#include "Utils/Base/Core.h"
#include "Shared/Resources/ResourceFileInfo.h"

namespace Engine
{
namespace Utils
{



	//
	// UI Localization Pack
	//

	class UILocale
	{
	// types
	public:
		typedef uint	StringID_t;		// 2 bytes to file ID, 2 bytes to string ID

	private:
		enum
		{
			FILE_ID_MASK	= 0xFFFF,
			FILE_ID_OFFSET	= 16,

			STR_ID_MASK		= 0xFFFF,
			STR_ID_OFFSET	= 0,
		};


	// variables
	private:
		Ptr<UtilsCore>	_core;
		string_array_t	_strings,
						_resources;
		uint			_fileID;


	// metadata
	public:
		static CMetaClass &		MetaUILocale ()	{ static CMetaClass metaClass;  return metaClass; }
		
		friend UX_CREATE_META_OBJECT( UILocale,  MetaUILocale() );

		CMetaSetIterator *		GetMetaIterator ()	{ return MetaUILocale().GetSetIter( *this ); }

		void InitMetaData ()
		{
			if ( not MetaUILocale().IsInit() )
			{
				CMetaAddIteratorPtr	iter;

				MetaUILocale().CreateExt( "UILocale", *this );
				iter = MetaUILocale().GetAddIter( *this );

				iter->AddField( _strings,	"strings" );
				iter->AddField( _resources,	"resources" );
			}
		}


	// methods
	public:
		UILocale () : _fileID(0)
		{
			InitMetaData();
		}
		
		UILocale (Ptr<UtilsCore> core) : _core(core), _fileID(0)
		{
			InitMetaData();
		}


		bool Load (uint fileID, uni_c_string path, const string_array_t &inputFiles)
		{
			CHECK_ERR( not inputFiles.Empty() and fileID != 0 );

			string	fname;

			FOR( i, inputFiles )
			{
				FileAddressUtils::BuildPath( fname, path, inputFiles[i], "ocf" );

				if ( i == 0 ) {
					CHECK_ERR( _Load( fname, fileID ) );
				} else {
					CHECK_ERR( _Append( fname ) );
				}
			}
			return true;
		}


		bool Save (uni_c_string filename)
		{
			MetaData::UILocaleCfg	locale_cfg;

			for (usize i = 0; i+1 < _strings.Count(); i += 2)
			{
				MetaData::ExtStringCfg	str( _strings[i+1] );

				locale_cfg.strings.PushBack( str );
			}

			
			WFilePtr	file;
			CHECK_ERR( (file = File::HddWFile::New( filename )).IsNotNull() );

			RESFILE_WRITE_HEADER( file, UILocaleFileInfo );

			locale_cfg.Serialize( file );
			return true;
		}


		bool Validate (const UILocale *loc)
		{
			CHECK_ERR( _strings.Count() == loc->_strings.Count() );

			string_array_t	strings;
			strings.SwapMem( _strings );

			for (usize i = 0; i+1 < loc->_strings.Count(); i += 2)
			{
				_strings.PushBack( loc->_strings[i] );

				usize	idx = -1;
				CHECK_ERR( _FindString( _strings.Back(), strings, idx ) );

				_strings.PushBack( strings[idx+1] );

				strings.Erase( idx, 2 );
			}

			CHECK_ERR( strings.Empty() );
			CHECK_ERR( _strings.Count() == loc->_strings.Count() );

			return true;
		}


		void Clear ()
		{
			_strings.Clear();
			_resources.Clear();
		}


		StringID_t GetStringId (uni_c_string str) const
		{
			for (usize i = 0; i+1 < _strings.Count(); i += 2)
			{
				if ( _strings[i] == str )
				{
					return _BuildStringID( _fileID, i/2 + 1 );
				}
			}
			return 0;
		}
		

	private:

		static bool _FindString (uni_c_string str, const string_array_t &strings, OUT usize &idx)
		{
			for (usize i = 0; i+1 < strings.Count(); i += 2)
			{
				if ( str == strings[i] )
				{
					idx = i;
					return true;
				}
			}
			return false;
		}


		bool _Load (uni_c_string filename, uint fileID)
		{
			Clear();

			static_obj_tree_t	cfg_tree;
			
			cfg_tree.Push( TConfigObjInfo( MetaUILocale().GetSetIter( *this ), null ) );
			
			CHECK_ERR( _core->Parse( filename, cfg_tree ) );


			CHECK_ERR( IsEven( _strings.Count() ) );
			CHECK_ERR( IsEven( _resources.Count() ) );

			_fileID = fileID;
			return true;
		}


		bool _Append (uni_c_string filename)
		{
			string_array_t	strings,
							resources;

			strings.SwapMem( _strings );
			resources.SwapMem( _resources );


			static_obj_tree_t	cfg_tree;
			
			cfg_tree.Push( TConfigObjInfo( MetaUILocale().GetSetIter( *this ), null ) );
			
			CHECK_ERR( _core->Parse( filename, cfg_tree ) );
			

			CHECK_ERR( IsEven( _strings.Count() ) );
			CHECK_ERR( IsEven( _resources.Count() ) );

			_strings.AppendFront( strings );
			_resources.AppendFront( resources );
			
			return true;
		}


		static StringID_t _BuildStringID (uint fileID, uint strID)
		{
			return	( ( fileID & FILE_ID_MASK ) << FILE_ID_OFFSET ) |
					( ( strID  & STR_ID_MASK  ) << STR_ID_OFFSET  );
		}
	};



	//
	// Localization Files for one language
	//
	/*
	class UILocalePack
	{
	// variables
	private:
		Ptr<UtilsCore>					_core;
		UILocale						_locale;
		MetaData::UILocaleLanguageCfg	_settings;


	// methods
	public:
		UILocalesArray (Ptr<UtilsCore> core) : _core(core)
		{}

		UILocale * GetLocale ()
		{
		}

		bool Load (uni_c_string path, uni_c_string settings, uint fileID)
		{
			string				fname;
			IFilePtr			file;
			static_obj_tree_t	cfg_tree;

			// load settings
			fname = StringUtils::AddToPath( path, settings );
			
			cfg_tree.Push( TConfigObjInfo( _settings.GetMetaIterator(), null ) );
			
			CHECK_ERR( _core->Parse( fname, cfg_tree ) );



			// load locale files
			string_array_t	files;

			CHECK_ERR( FILESYS()->GetAllFilesInPath( path.cstr(), files ) );

			FOR( i, files )
			{
				if ( files[i] == settings or files[i] == "." or files[i] == ".." )
					continue;

				if ( StringUtils::GetFileExt( files[i] ) != ".ocf" )
					continue;

				cfg_tree.Clear();
				
				fname = StringUtils::AddToPath( path, (uni_c_string) files[i] );

				UILocalePtr	locale = new UILocale( _core );

				if ( _locales.Empty() ) {
					CHECK_ERR( locale->Load( fname, fileID ) );
				}
				else {
					CHECK_ERR( locale->Append( fname ) );
				}

				_locales.PushBack( locale );
			}
		}
	};*/


}	// Utils
}	// Engine
